package com.shop.jpa;

import com.shop.jpa.domain.BasePage;
import com.shop.jpa.support.QuerySQL;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.List;
import java.util.Map;

/**
 * 执行原生 SQL Repository（MySQL）
 * 
 * @author Jerry  2018-8-8 12:09:44
 */
@NoRepositoryBean
public abstract class BaseSQLDao {

	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	/**
	 * 计数
	 * @param querySQL
	 * @return
	 */
	protected int count(QuerySQL querySQL) {
		Integer ret = jdbcTemplate.queryForObject(querySQL.getCountSql(), querySQL.getParams(), Integer.class);
		return null == ret ? 0 : ret;
	}

	/**
	 * 查询 List<T>
	 * @param targetClass
	 * @return
	 */
	protected <T> List<T> query(QuerySQL querySQL, Class<T> targetClass) {
		return jdbcTemplate.query(querySQL.getQuerySql(), querySQL.getParams(), new BeanPropertyRowMapper<>(targetClass));
	}

	/**
	 * 查询单个实例
	 * @param querySQL
	 * @param targetClass
	 * @return
	 */
	protected <T> T querySingle(QuerySQL querySQL, Class<T> targetClass) {
		try {
			return jdbcTemplate.queryForObject(querySQL.getQuerySql(), querySQL.getParams(), new BeanPropertyRowMapper<>(targetClass));
		} catch (EmptyResultDataAccessException erdaException) {
			return null;
		}
	}

	/**
	 * 分页查询 List<T>
	 * @param querySQL
	 * @param targetClass
	 * @return
	 */
	protected <T> List<T> pageQuery(QuerySQL querySQL, Class<T> targetClass) {
		return jdbcTemplate.query(querySQL.getPageSql(), querySQL.getParams(), new BeanPropertyRowMapper<T>(targetClass));
	}
	
	/**
	 * 分页查询 Page<T>
	 * @param querySQL
	 * @param targetClass
	 * @return
	 */
	protected <T> Page<T> page(QuerySQL querySQL, Class<T> targetClass) {
		List<T> list = this.pageQuery(querySQL, targetClass);
		int count = this.count(querySQL);
		return new BasePage<>(list, PageRequest.of(querySQL.getPageNo(), querySQL.getPageSize()), count);
	}

	/**
	 * 查询单个实例，返回Map<String, Object>对象
	 * @param querySQL
	 * @return
	 */
	protected Map<String, Object> queryForMap(QuerySQL querySQL) {
		return jdbcTemplate.queryForMap(querySQL.getQuerySql(), querySQL.getParams());
	}
	
	/**
	 * 查询 List<Map<String, Object>>
	 * @return
	 */
	protected List<Map<String, Object>> queryForListMap(QuerySQL querySQL) {
		return jdbcTemplate.queryForList(querySQL.getQuerySql(), querySQL.getParams());
	}
	


	/**
	 * 分页查询 List<Map<String, Object>>
	 * @param querySQL
	 * @return
	 */
	protected List<Map<String, Object>> pageQueryListMap(QuerySQL querySQL) {
		return jdbcTemplate.queryForList(querySQL.getPageSql(), querySQL.getParams());
	}
	
	/**
	 * 分页查询 Page<Map<String, Object>>
	 * @param querySQL
	 * @return
	 */
	protected Page<Map<String, Object>> pageForListMap(QuerySQL querySQL) {
		List<Map<String, Object>> list = this.pageQueryListMap(querySQL);
		int count = this.count(querySQL);
		return new BasePage<>(list, PageRequest.of(querySQL.getPageNo(), querySQL.getPageSize()), count);
	}
	
	/**
	 * TODO 执行存储过程
	 */
	protected void call() {
	}

	/**
	 * 更新
	 * @param sql
	 * @param args
	 * @return
	 */
	protected int update(String sql, Object... args) {
		return jdbcTemplate.update(sql, args);
	}

	/**
	 * 直接查询SQL
	 * @param sql
	 * @param targetClass
	 * @param <T>
	 * @return
	 */
	protected <T> T queryObject(String sql,Class<T> targetClass) {
		return jdbcTemplate.queryForObject(sql,getRowMapper(targetClass));
	}
	/**
	 * 直接查询SQL
	 * @param sql
	 * @param targetClass
	 * @param <T>
	 * @return
	 */
	protected <T> List<T> query(String sql,Class<T> targetClass) {
		return jdbcTemplate.query(sql,getRowMapper(targetClass));
	}

	/**
	 * 定义字段映射
	 * @param targetClass
	 * @param <T>
	 * @return
	 */
	private <T> BeanPropertyRowMapper<T> getRowMapper(Class<T> targetClass) {
		BeanPropertyRowMapper<T> rowMapper = new BeanPropertyRowMapper<T>(targetClass){
			@Override
			protected void initBeanWrapper(BeanWrapper bw) {
				super.initBeanWrapper(bw);
			}
		};
		return rowMapper;
	}


}
